home *** CD-ROM | disk | FTP | other *** search
- /*************************************************************************************************
- *
- *
- * MacZoop - "the framework for the rest of us"
- *
- *
- *
- * ZStream.h -- a generic stream (abstract class- use ZHandleStream or
- * ZFileStream ).
- *
- *
- *
- *
- *
- * © 1998, Graham Cox
- *
- *
- *
- *
- *************************************************************************************************/
-
- #include "ZStream.h"
- #include "ZArray.h"
- #include "ZObject.h"
- #include "ZDefines.h"
- #include "ZErrors.h"
- #include "ZClassRegistry.h"
-
-
- /*--------------------------------*** CONSTRUCTOR ***-----------------------------------*/
-
-
- ZStream::ZStream()
- {
- mark = 0;
- idSeed = 1;
-
- refTable = NULL;
- }
-
-
- /*---------------------------------*** DESTRUCTOR ***----------------------------------*/
-
-
- ZStream::~ZStream()
- {
- if ( refTable )
- ForgetObject( refTable );
- }
-
-
-
- /*----------------------------------*** READCHAR ***-----------------------------------*/
- /*
- read the next character from the stream
- -----------------------------------------------------------------------------------------*/
-
- void ZStream::ReadChar( char* aChar )
- {
- long dlen = sizeof( char );
-
- GetFrom( aChar, &dlen );
- }
-
-
- /*---------------------------------*** READSHORT ***-----------------------------------*/
- /*
- read the next short word from the stream
- -----------------------------------------------------------------------------------------*/
-
- void ZStream::ReadShort( short* aShort )
- {
- long dlen = sizeof( short );
-
- GetFrom( aShort, &dlen );
- }
-
-
- /*----------------------------------*** READLONG ***-----------------------------------*/
- /*
- read the next long word from the stream
- -----------------------------------------------------------------------------------------*/
-
- void ZStream::ReadLong( long* aLong )
- {
- long dlen = sizeof( long );
-
- GetFrom( aLong, &dlen );
- }
-
-
- /*---------------------------------*** READFLOAT ***-----------------------------------*/
- /*
- read the next floating point value from the stream
- -----------------------------------------------------------------------------------------*/
-
- void ZStream::ReadFloat( float* aFloat )
- {
- long dlen = sizeof( float );
-
- GetFrom( aFloat, &dlen );
- }
-
-
- /*---------------------------------*** READSTRING ***----------------------------------*/
- /*
- read the next pascal string from the stream
- -----------------------------------------------------------------------------------------*/
-
- void ZStream::ReadString( Str255 aString )
- {
- char slen;
- long dlen;
-
- ReadChar( &slen );
- dlen = (long) slen + 1;
- Skip( -1 );
- GetFrom((Ptr) aString, &dlen );
- }
-
-
- /*----------------------------------*** READDATA ***-----------------------------------*/
- /*
- read arbitrary block of data from the stream. Data is stored as length (long word) followed
- by the data bytes.
- -----------------------------------------------------------------------------------------*/
-
- void ZStream::ReadData( Ptr aBuf, long* dataLen )
- {
- // if you pass NULL in <aBuf>, you can read the size and skip the rest of the
- // data if you want to allocate space first- you should then skip back by
- // dataLen + 4 to re-read the data. Alternatively read the size using ReadLong first,
- // then skip back 4 to call this.
-
- ReadLong( dataLen );
-
- if ( aBuf )
- GetFrom( aBuf, dataLen );
- else
- Skip( *dataLen );
- }
-
-
- /*---------------------------------*** READHANDLE ***----------------------------------*/
- /*
- read data from stream into handle- handle is resized to suit. Handle data is stored as
- length (long word) followed by handle content bytes
- -----------------------------------------------------------------------------------------*/
-
- void ZStream::ReadHandle( Handle* aHand )
- {
- Handle h;
- long hs;
-
- FailNILParam( aHand );
- ReadLong( &hs );
-
- if ( hs == 'null' )
- h = NULL;
- else
- {
- FailNIL( h = NewHandle( hs ));
-
- HLock( h );
- GetFrom( *h, &hs );
- HUnlock( h );
- }
-
- *aHand = h;
- }
-
-
- /*-----------------------------*** READOBJECTREFERENCE ***-----------------------------*/
- /*
- return an object from the stream. This correctly returns objects referred multiply within
- a single stream.
- -----------------------------------------------------------------------------------------*/
-
- ZObject* ZStream::ReadObject()
- {
- long classID, instanceID, index;
- ObjRef_T_Entry oti;
- ZObject* theObj = NULL;
-
- #if _MACZOOP_STREAMS
-
- if ( refTable == NULL )
- FailNIL( refTable = new ZArray( sizeof( ObjRef_T_Entry )));
-
- ReadLong( &classID );
- ReadLong( &instanceID );
-
- // check for the special 'null' marker- if it's there, we just return NULL since there's
- // nothing else to do.
-
- if ( classID != 'null' )
- {
- index = FindObjectReference( classID, instanceID );
-
- if ( index > 0 )
- {
- // we encountered this one earlier, so return the ref we made then
-
- refTable->GetArrayItem( &oti, index );
-
- theObj = oti.theObject;
- }
- else
- {
- // this is a new one, so make it by calling the class registry to construct
- // it, then pass the stream to the object to initialise its data. We also
- // make an entry in the ref table for it in case something refers to it
- // further along the stream. The class registry assumes the next data in
- // the stream is the class ID, so wind the stream back 8 bytes first...
-
- Skip( -2 * sizeof( long ));
-
- // build the object. In order to work, the object class must have been registered with
- // <gClasses> at some point previously. This is normally done at app startup time.
-
- theObj = gClasses->InstantiateFromStream( this );
-
- // store a ref to it for later. For this to work, it is IMPERATIVE that stream users
- // do not delete any objects obtained from the stream until the stream itself is no
- // longer needed, otherwise this technique will fail big time.
-
- oti.theObject = theObj;
- oti.classID = classID;
- oti.instanceID = instanceID;
-
- refTable->AppendItem( &oti );
- }
- }
- #else
- FailOSErr( kStreamsNotPresentErr );
-
- #endif
-
- return theObj;
- }
-
-
- /*----------------------------------*** READRECT ***-----------------------------------*/
- /*
- read a quickdraw rect from the stream
- -----------------------------------------------------------------------------------------*/
-
- void ZStream::ReadRect( Rect* aRect )
- {
- long dLen = sizeof( Rect );
- GetFrom( aRect, &dLen );
- }
-
-
- /*---------------------------------*** READPOINT ***-----------------------------------*/
- /*
- read a quickdraw point from the stream
- -----------------------------------------------------------------------------------------*/
-
- void ZStream::ReadPoint( Point* aPoint )
- {
- long dLen = sizeof( Point );
- GetFrom( aPoint, &dLen );
- }
-
-
- /*-------------------------------*** READGRAFPORT ***----------------------------------*/
- /*
- read the state of a grafport from the stream
- -----------------------------------------------------------------------------------------*/
-
- void ZStream::ReadGrafPort( GrafPtr aPort )
- {
- GrafPtr savePort;
- RgnHandle clip;
- PenState ps;
- char ffc;
- short ffs;
- long ffl;
- RGBColor cc;
- Str255 fontName;
-
- FailNILParam( aPort );
-
- GetPort( &savePort );
- SetPort( aPort );
-
- ReadRect( &aPort->portRect );
- ReadHandle((Handle*) &clip );
-
- if ( clip )
- {
- SetClip( clip );
- DisposeRgn( clip );
- }
-
- ffl = sizeof( PenState );
- ReadData((Ptr) &ps, &ffl );
- SetPenState( &ps );
-
- ReadHandle((Handle*) &clip );
-
- if ( clip )
- {
- CopyRgn( clip, aPort->visRgn );
- DisposeRgn( clip );
- }
-
- ReadShort( &ffs );
- TextSize( ffs );
- ReadShort( &ffs );
- TextMode( ffs );
- ReadChar( &ffc );
- TextFace((Style) ffc );
- ReadLong( &ffl );
- SpaceExtra((Fixed) ffl );
-
- ReadString( fontName );
- GetFNum( fontName, &ffs );
- TextFont( ffs );
-
- ReadColour( &cc );
- RGBForeColor( &cc );
- ReadColour( &cc );
- RGBBackColor( &cc );
-
- SetPort( savePort );
- }
-
-
- /*--------------------------------*** READCOLOUR ***-----------------------------------*/
- /*
- read a rgb colour from the stream
- -----------------------------------------------------------------------------------------*/
-
- void ZStream::ReadColour( RGBColor* rgb )
- {
- long dlen = sizeof( RGBColor );
- GetFrom( rgb, &dlen );
- }
-
-
- /*---------------------------------*** WRITECHAR ***-----------------------------------*/
- /*
- write a single character to the stream
- -----------------------------------------------------------------------------------------*/
-
- void ZStream::WriteChar( char aChar )
- {
- PutTo( &aChar, sizeof( char ));
- }
-
-
- /*--------------------------------*** WRITESHORT ***-----------------------------------*/
- /*
- write a single short word to the stream
- -----------------------------------------------------------------------------------------*/
-
- void ZStream::WriteShort( short aShort )
- {
- PutTo( &aShort, sizeof( short ));
- }
-
-
- /*---------------------------------*** WRITELONG ***-----------------------------------*/
- /*
- write a single long word to the stream
- -----------------------------------------------------------------------------------------*/
-
- void ZStream::WriteLong( long aLong )
- {
- PutTo( &aLong, sizeof( long ));
- }
-
-
- /*--------------------------------*** WRITEFLOAT ***----------------------------------*/
- /*
- write a single floating point value to the stream
- -----------------------------------------------------------------------------------------*/
-
- void ZStream::WriteFloat( float aFloat )
- {
- PutTo( &aFloat, sizeof( float ));
- }
-
-
- /*--------------------------------*** WRITESTRING ***----------------------------------*/
- /*
- write a single pascal string to the stream
- -----------------------------------------------------------------------------------------*/
-
- void ZStream::WriteString( Str255 aString )
- {
- PutTo( aString, aString[0] + 1 );
- }
-
-
- /*---------------------------------*** WRITEDATA ***-----------------------------------*/
- /*
- write an arbitrary block of data to the stream
- -----------------------------------------------------------------------------------------*/
-
- void ZStream::WriteData( Ptr aBuf, long dataLen )
- {
- // arbitrary data is written as a length count, followed by the data.
-
- FailNILParam( aBuf );
- WriteLong( dataLen );
- PutTo( aBuf, dataLen );
- }
-
-
- /*--------------------------------*** WRITEHANDLE ***----------------------------------*/
- /*
- write contents of any handle to the stream. It's OK for the handle to be NULL.
- -----------------------------------------------------------------------------------------*/
-
- void ZStream::WriteHandle( Handle aHand )
- {
- if ( aHand )
- {
- long hs = GetHandleSize( aHand );
- char hState = HGetState( aHand );
-
- // handles are written with their size followed by the data
-
- WriteLong( hs );
-
- HLock( aHand );
-
- PutTo( *aHand, hs );
- HSetState( aHand, hState );
- }
- else
- WriteLong( 'null' );
- }
-
-
- /*----------------------------*** WRITEOBJECTREFERENCE ***-----------------------------*/
- /*
- write an object reference to the stream. This returns <TRUE> if you are expected to write
- further data to the stream for the object, or <FALSE> if this was already done for this
- object earlier.
- -----------------------------------------------------------------------------------------*/
-
- void ZStream::WriteObject( ZObject* anObject )
- {
- // to write an object reference, we assign it an instance ID and gets its class ID-
- // these are then written to the file. If the same object is written again later, we
- // write the same IDs as before.
-
- #if _MACZOOP_STREAMS
- Boolean wasWritten = FALSE;
-
- if ( refTable == NULL )
- FailNIL( refTable = new ZArray( sizeof( ObjRef_T_Entry )));
-
- ObjRef_T_Entry oti;
- long index = FindObjectReference( anObject );
-
- if ( anObject && ( index > 0 ))
- {
- // we've seen this one before, so get its IDs and write them to the stream
-
- refTable->GetArrayItem( &oti, index );
- }
- else
- {
- // nope, this is a new one on me, so create an entry for it in the table and
- // write the data to the stream. The instance ID itself is not significant- all
- // that matters is that it is unique for the given class/instance. We just allocate
- // a sequential number from our seed.
-
- // if the object is NULL, we write a special marker to the stream to tell us to return
- // NULL when the stream is read back in.
-
- if ( anObject == NULL )
- {
- oti.classID = 'null';
- oti.instanceID = '0000';
- }
- else
- {
- oti.theObject = anObject;
- oti.instanceID = idSeed++;
- oti.classID = anObject->GetClassRef();
-
- refTable->AppendItem( &oti );
-
- wasWritten = TRUE;
- }
- // for the first instance of an object encountered, the caller is expected to write the
- // object's state data immediately following. If this function returns TRUE, you should
- // write this data, otherwise do not bother.
- }
-
- PutTo( &oti.classID, sizeof( long ));
- PutTo( &oti.instanceID, sizeof( long ));
-
- if ( wasWritten )
- anObject->WriteToStream( this );
- #else
- FailOSErr( kStreamsNotPresentErr );
-
- #endif
- }
-
-
- /*---------------------------------*** WRITERECT ***-----------------------------------*/
- /*
- write quickdraw rectangle to the stream
- -----------------------------------------------------------------------------------------*/
-
- void ZStream::WriteRect( Rect* aRect )
- {
- PutTo( aRect, sizeof( Rect ));
- }
-
-
- /*---------------------------------*** WRITEPOINT ***----------------------------------*/
- /*
- write quickdraw point to the stream
- -----------------------------------------------------------------------------------------*/
-
- void ZStream::WritePoint( Point aPoint )
- {
- PutTo( &aPoint, sizeof( Point ));
- }
-
-
- /*-------------------------------*** WRITEGRAFPORT ***---------------------------------*/
- /*
- write quickdraw grafport state to stream (pen, font, etc)
- -----------------------------------------------------------------------------------------*/
-
- void ZStream::WriteGrafPort( GrafPtr aPort )
- {
- FailNILParam( aPort );
-
- GrafPtr savePort;
- PenState ps;
- RgnHandle clip;
- RGBColor cc;
- Str255 fontName;
-
- GetPort( &savePort );
- SetPort( aPort );
- GetPenState( &ps );
- GetClip( clip = NewRgn());
-
- WriteRect( &aPort->portRect );
- WriteHandle((Handle) clip );
- WriteData((Ptr) &ps, sizeof( PenState ));
-
- CopyRgn( aPort->visRgn, clip );
- WriteHandle((Handle) clip );
-
- WriteShort( aPort->txSize );
- WriteShort( aPort->txMode );
- WriteChar((char) aPort->txFace );
- WriteLong((long) aPort->spExtra );
-
- GetFontName( aPort->txFont, fontName );
- WriteString( fontName );
-
- GetForeColor( &cc );
- WriteColour( &cc );
- GetBackColor( &cc );
- WriteColour( &cc );
-
- DisposeRgn( clip );
- SetPort( savePort );
- }
-
-
- /*--------------------------------*** WRITECOLOUR ***----------------------------------*/
- /*
- write rgb colour to the stream
- -----------------------------------------------------------------------------------------*/
-
- void ZStream::WriteColour( RGBColor* rgb )
- {
- PutTo( rgb, sizeof( RGBColor ));
- }
-
-
- /*----------------------------*** FINDOBJECTREFERENCE ***------------------------------*/
- /*
- return index of object in local temporary reference table (internal method)
- -----------------------------------------------------------------------------------------*/
-
- long ZStream::FindObjectReference( ZObject* anObject )
- {
- long i;
- ObjRef_T_Entry oti;
-
- for( i = 1; i <= refTable->CountItems(); i++ )
- {
- refTable->GetArrayItem( &oti, i );
-
- if ( oti.theObject == anObject )
- return i;
- }
-
- return 0;
- }
-
-
- /*----------------------------*** FINDOBJECTREFERENCE ***------------------------------*/
-
- long ZStream::FindObjectReference( long classID, long instanceID )
- {
- long i;
- ObjRef_T_Entry oti;
-
- for( i = 1; i <= refTable->CountItems(); i++ )
- {
- refTable->GetArrayItem( &oti, i );
-
- if (( oti.classID == classID ) &&
- ( oti.instanceID == instanceID ))
- return i;
- }
-
- return 0;
- }
-